package cn.signalpha.modules.auth.granter;

import cn.signalpha.common.cache.CacheNames;
import cn.signalpha.common.cache.ParamCache;
import cn.signalpha.core.log.exception.ServiceException;
import cn.signalpha.core.redis.cache.RedisCache;
import cn.signalpha.core.tool.utils.DigestUtil;
import cn.signalpha.core.tool.utils.Func;
import cn.signalpha.core.tool.utils.StringUtil;
import cn.signalpha.core.tool.utils.WebUtil;
import cn.signalpha.modules.auth.dto.UserInfo;
import cn.signalpha.modules.auth.enums.UserEnum;
import cn.signalpha.modules.auth.provider.ITokenGranter;
import cn.signalpha.modules.auth.provider.TokenParameter;
import cn.signalpha.modules.auth.utils.TokenUtil;
import cn.signalpha.modules.com.service.UserService;
import cn.signalpha.modules.shop.service.SellerService;
import cn.signalpha.modules.system.service.IUserService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.time.Duration;

/**
 * 验证码TokenGranter
 */
@Component
@AllArgsConstructor
public class CaptchaTokenGranter implements ITokenGranter {

	public static final String GRANT_TYPE = "captcha";
	public static final Integer FAIL_COUNT = 5;
	public static final String FAIL_COUNT_VALUE = "account.failCount";

	private final RedisCache redisCache;
	private final UserService userService;
	private final IUserService sysUserService;
	private final SellerService sellerService;

	@Override
	public UserInfo grant(TokenParameter tokenParameter) {
		HttpServletRequest request = WebUtil.getRequest();

		String key = request.getHeader(TokenUtil.CAPTCHA_HEADER_KEY);
		String code = request.getHeader(TokenUtil.CAPTCHA_HEADER_CODE);
		// 获取验证码
		String redisCode = redisCache.get(CacheNames.CAPTCHA_KEY + key);
		// 判断验证码
		if (code == null || !StringUtil.equalsIgnoreCase(redisCode, code)) {
			throw new ServiceException(TokenUtil.CAPTCHA_NOT_CORRECT);
		}

		String username = tokenParameter.getArgs().getStr("username");
		String password = tokenParameter.getArgs().getStr("password");

		// 判断登录是否锁定
		int cnt = Func.toInt(redisCache.get(CacheNames.cacheKey(CacheNames.USER_FAIL_KEY, username)), 0);
		int failCount = Func.toInt(ParamCache.getValue(FAIL_COUNT_VALUE), FAIL_COUNT);
		if (cnt >= failCount) {
			throw new ServiceException(TokenUtil.USER_HAS_TOO_MANY_FAILS);
		}

		UserInfo userInfo = null;
		if (Func.isNoneBlank(username, password)) {
			// 获取用户类型
			String userType = tokenParameter.getArgs().getStr("userType");
			// 根据不同用户类型调用对应的接口返回数据，用户可自行拓展
			if (userType.equals(UserEnum.WEB.getName())) {
				userInfo = sysUserService.userInfo(username, DigestUtil.hex(password));
			} else if (userType.equals(UserEnum.WAP.getName())) {
				userInfo = userService.userInfo(username, DigestUtil.hex(password));
			} else if (userType.equals(UserEnum.SELLER.getName())) {
				userInfo = sellerService.userInfo(username, DigestUtil.hex(password));
			} else {
				throw new ServiceException("无效的用户类型");
			}
		}
		if (userInfo == null) {
			// 增加错误锁定次数
			redisCache.setEx(CacheNames.cacheKey(CacheNames.USER_FAIL_KEY, username), cnt + 1, Duration.ofMinutes(10));
		} else {
			// 成功则清除登录缓存
			redisCache.del(CacheNames.cacheKey(CacheNames.USER_FAIL_KEY, username));
			redisCache.del(CacheNames.CAPTCHA_KEY + key);
		}
		return userInfo;
	}

}
